package com.xqboss.apps.service.user;


import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sun.org.apache.bcel.internal.generic.NEW;
import com.xqboss.apps.domain.consumer.ConsumerInviteRecord;
import com.xqboss.apps.domain.consumer.ConsumerRealName;
import com.xqboss.apps.domain.user.*;
import com.xqboss.apps.dto.user.WrenchReferrerQueryDto;
import com.xqboss.apps.dto.user.upWrenchFactoryDto;
import com.xqboss.apps.enums.user.*;
import com.xqboss.apps.mapper.user.UserAssetWrenchMapper;
import com.xqboss.apps.service.consumer.ConsumerInviteRecordService;
import com.xqboss.apps.service.consumer.ConsumerRealNameService;
import com.xqboss.apps.service.nft.NftNumberService;
import com.xqboss.apps.service.nft.NftService;
import com.xqboss.apps.vo.user.*;
import com.xqboss.common.core.domain.R;
import com.xqboss.common.core.domain.entity.SysUser;
import com.xqboss.common.exception.ServiceException;
import com.xqboss.system.service.ISysUserService;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneOffset;
import java.time.temporal.ChronoUnit;
import java.util.Date;
import java.util.List;
import java.util.Optional;


/**
 * 用户资产-扳手(UserAssetWrench)表服务实现类
 *
 * @author makejava
 * @since 2023-12-07 14:09:52
 */
@Service
public class UserAssetWrenchService extends ServiceImpl<UserAssetWrenchMapper, UserAssetWrench> {

    @Autowired
    private ConsumerInviteRecordService consumerInviteRecordService;

    @Autowired
    private UserAssetWrenchRecordService userAssetWrenchRecordService;

    @Autowired
    private UserAssetWrenchReceiveService userAssetWrenchReceiveService;

    @Autowired
    private ISysUserService sysUserService;

    @Autowired
    private UserIdentityPermWrenchService userIdentityPermWrenchService;

    @Autowired
    private ConsumerRealNameService consumerRealNameService;

    @Autowired
    private NftService nftService;

    @Autowired
    private NftNumberService nftNumberService;

    @Autowired
    private UserWrenchProductionRecordService userWrenchProductionRecordService;
    @Autowired
    private UserIdentityPermWrenchProductionService userIdentityPermWrenchProductionService;
    @Autowired
    private SysUserWalletService sysUserWalletService;
    @Autowired
    private UserIdentityRankService userIdentityRankService;

    /**
     * 新增扳手钱包-用户注册时
     *
     * @param username
     */
    public void addWrenchByUserName(String username) {
        SysUser user = sysUserService.selectUserByUserName(username);
        if (user == null) {
            return;
        }
        UserAssetWrench wrench = new UserAssetWrench();
        wrench.setUserId(user.getUserId());
        this.save(wrench);
    }

    /**
     * 通过用户id获取扳手资产信息
     *
     * @param userId
     * @return
     */
    public UserAssetWrench getByUserId(Long userId) {
        return this.lambdaQuery()
                .eq(UserAssetWrench::getUserId, userId)
                .one();
    }

    /**
     * 首页信息
     *
     * @return
     */
    public WrenchIndexVo indexInfo(Long userId) {
        UserAssetWrench wrench = this.getByUserId(userId);
        WrenchIndexVo vo = new WrenchIndexVo();
        vo.setWrenchTotalNum(wrench.getTotal());
        vo.setWrenchPendingNum(wrench.getPending());
        vo.setInviteRealNum(consumerInviteRecordService.getInviteNum(userId));

        // 今日新增=扳手工厂的今日产出+今日邀请获得扳手
        // 计算今日邀请获得的扳手
        LambdaQueryWrapper<UserAssetWrenchReceive> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper
                .eq(UserAssetWrenchReceive::getUserId, userId)
                .between(UserAssetWrenchReceive::getCreateTime, DateUtil.beginOfDay(new Date()), DateUtil.endOfDay(new Date()));
        List<UserAssetWrenchReceive> list = userAssetWrenchReceiveService.list(lambdaQueryWrapper);
        // 邀请获得的扳手
        BigDecimal inviteAmount = new BigDecimal(0);
        for (UserAssetWrenchReceive wrenchReceive : list) {
            inviteAmount = inviteAmount.add(wrenchReceive.getAmount());
        }
        //【累计扳手】更改为【好友贡献】 判断是否是今天的数据 页面根据这个显示红点
        vo.setIsToDay(inviteAmount.compareTo(BigDecimal.ZERO) > 0);
        // 计算今日生产扳手
        BigDecimal productionAmount = todayWrenchInsert(userId);

        vo.setInsertToday(inviteAmount.add(productionAmount));
        // 返回工厂状态 生产中/已停产/已完工
        UserWrenchProductionRecord record = getUserWrenchProductionRecord(userId);
        if (record == null) {
            vo.setStatus(WrenchProductionTypeEnum.ALREADY_GET.getValue());
            return vo;
        }
        // 可领取的时间/结算完成的时间
        long plusTime = record.getStartTime().plusDays(record.getPredictDay() + 1).toLocalDate().atTime(0, 0, 0)
                .atZone(ZoneOffset.UTC).toInstant().toEpochMilli();
        // 当前时间
        long today = LocalDateTime.now().toInstant(ZoneOffset.UTC).toEpochMilli();
        // 生产完成时间/结算时间
        long endTime = record.getStartTime().plusDays(record.getPredictDay()).toInstant(ZoneOffset.UTC).toEpochMilli();
        // 如果已经领取,则不再计算
        if (record.getGetAmount() != null){
            vo.setStatus(record.getStatus());
            return vo;
        }
        // 未领取状态
        if (plusTime <= today) {// 已超过结算期的时间 可以领取
                vo.setStatus(WrenchProductionTypeEnum.WAIT_GET.getValue());
                record.setStatus(WrenchProductionTypeEnum.WAIT_GET.getValue());
        }else if (endTime <= today){// 结算中
            vo.setStatus(WrenchProductionTypeEnum.CLOSING.getValue());
            record.setStatus(WrenchProductionTypeEnum.CLOSING.getValue());
        }else { // 生产中
            vo.setStatus(WrenchProductionTypeEnum.IN_PRODUCTION.getValue());
            record.setStatus(WrenchProductionTypeEnum.IN_PRODUCTION.getValue());
        }
        userWrenchProductionRecordService.updateById(record);
        return vo;
    }


    /**
     * 计算今日生产扳手
     *
     * @param userId
     * @return
     */
    @NotNull
    private BigDecimal todayWrenchInsert(Long userId) {
        // 计算今日扳手工厂产出
        // 1.查出启动套餐 按小时计算查出昨天到24点的产出
        BigDecimal productionAmount = new BigDecimal(0);
        UserWrenchProductionRecord wrenchProductionRecord = getUserWrenchProductionRecord(userId);
        if (null == wrenchProductionRecord) {
            return productionAmount;
        }
        // 如果是已领取的状态且超过一天的则不计算
        if (wrenchProductionRecord.getEndTime() != null) {
            LocalDateTime endTime = wrenchProductionRecord.getEndTime().plusDays(1);
            if (ChronoUnit.DAYS.between( LocalDate.now(),endTime.toLocalDate()) >= 0) {
                return productionAmount;
            }
        }
        // predictHour = 一共需要生产的小时数
        int predictHour = wrenchProductionRecord.getPredictDay() * 24;
        BigDecimal predictOutputWrench = wrenchProductionRecord.getPredictOutputWrench();
        // avgHourWrench = 平均每小时产出
        BigDecimal avgHourWrench = predictOutputWrench.divide(BigDecimal.valueOf(predictHour), 2, RoundingMode.HALF_UP);
        // avgDayWrench = 平均每天产出
        BigDecimal avgDayWrench = predictOutputWrench.divide(BigDecimal.valueOf(wrenchProductionRecord.getPredictDay()), 2, RoundingMode.HALF_UP);
        LocalDateTime startTime = wrenchProductionRecord.getStartTime();
        LocalDateTime today = LocalDateTime.now();
        // 不是是启动生产当天 才有生产收益, 如果是查看第一天或者最后一天收益则按小时计算
        Integer predictDay = wrenchProductionRecord.getPredictDay();
        // 结算完成的时间
        LocalDateTime plusDays = wrenchProductionRecord.getStartTime().toLocalDate().plusDays(predictDay + 1).atTime(0,0,0);
        // 距离24点相差的小时数
        LocalDateTime time = startTime.toLocalDate().plusDays(1).atTime(0, 0, 0);
        long hour = ChronoUnit.HOURS.between(startTime, time);
        if (plusDays.toLocalDate().equals(LocalDate.now())) {// 最后一天收益
            // 生产了多少小时
            long productionHour = 24L-hour;
            productionAmount = avgHourWrench.multiply(BigDecimal.valueOf(productionHour)).setScale(2, RoundingMode.HALF_UP);
        } else if (startTime.plusDays(1).toLocalDate().equals(LocalDate.now())) {//第一天收益
            // 已生产的小时
            productionAmount = avgHourWrench.multiply(BigDecimal.valueOf(hour)).setScale(2, RoundingMode.HALF_UP);
        } else if (!(startTime.toLocalDate().equals(today.toLocalDate())) && ChronoUnit.DAYS.between(plusDays.toLocalDate(), today.toLocalDate()) < 0) {// 非第一天也非最后一天收益
            productionAmount = avgDayWrench;
        }
        return productionAmount;
    }

    /**
     * 校验日期否是今日
     *
     * @param time
     * @return
     */
    public Boolean checkIsToday(LocalDateTime time) {
        LocalDate today = LocalDate.now();
        LocalDate localDate = time.toLocalDate();
        return localDate.equals(today);
    }

    /**
     * 邀请用户列表
     *
     * @param param
     * @return
     */
    public List<WrenchReferrerVo> getReferrerList(WrenchReferrerQueryDto param) {
        return baseMapper.getReferrerList(param);
    }

    /**
     * 领取
     *
     * @param userId
     */
    @Transactional
    public BigDecimal receive(Long userId) {
        UserAssetWrench wrench = this.getByUserId(userId);
        if (wrench.getPending().compareTo(BigDecimal.ZERO) != 1) {
            throw new ServiceException("没有待领取的扳手");
        }

        List<UserAssetWrenchReceive> pendingList = userAssetWrenchReceiveService.lambdaQuery()
                .select(UserAssetWrenchReceive::getAmount, UserAssetWrenchReceive::getId)
                .eq(UserAssetWrenchReceive::getUserId, userId)
                .eq(UserAssetWrenchReceive::getIsReceive, 0)
                .list();
        BigDecimal pendingNum = pendingList.stream()
                .map(UserAssetWrenchReceive::getAmount)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        if (pendingNum.compareTo(wrench.getPending()) != 0) {
            throw new ServiceException("待领取扳手数量不正确");
        }

        // 更新余额
        Long recordId = userAssetWrenchRecordService.updateWrenchBalance(userId, WalletWrenchChangeTypeEnum.RECEIVE,
                WalletChangeDirectionEnum.IN, wrench.getPending(), null, WalletWrenchChangeTypeEnum.RECEIVE.getMsg());

        // 统计扳手更新
        boolean result = this.lambdaUpdate()
                .setSql("pending = pending -" + wrench.getPending())
                .setSql("total = total +" + wrench.getPending())
                .eq(UserAssetWrench::getId, wrench.getId())
                .update();
        if (!result) {
            throw new ServiceException("领取失败");
        }

        // 领取表设置记录id
        result = userAssetWrenchReceiveService.lambdaUpdate()
                .set(UserAssetWrenchReceive::getRecordId, recordId)
                .set(UserAssetWrenchReceive::getIsReceive, 1)
                .set(UserAssetWrenchReceive::getReceiveTime, new Date())
                .in(UserAssetWrenchReceive::getId, pendingList.stream().map(UserAssetWrenchReceive::getId).toArray())
                .eq(UserAssetWrenchReceive::getIsReceive, 0)
                .update();
        if (!result) {
            throw new ServiceException("领取失败");
        }
        return wrench.getPending();
    }


    /**
     * 消耗nft藏品时奖励上级扳手
     * 实名的上级才有奖励，根据身份奖励不同数量的扳手
     *
     * @param userId
     * @param nftNumberId
     */
    @Transactional
    public void rewardByUseNft(Long userId, Long nftNumberId) {
        Long nftId = nftNumberService.getNftNumber(nftNumberId).getNftId();
        // 判断该nft是否支持奖励
        List<UserIdentityPermWrench> list = userIdentityPermWrenchService.lambdaQuery()
                .eq(UserIdentityPermWrench::getUseNftId, nftId)
                .list();
        if (list == null || list.isEmpty()) {
            return;
        }
        // 判断是否存在上级
        ConsumerInviteRecord myInvite = consumerInviteRecordService.lambdaQuery()
                .eq(ConsumerInviteRecord::getUserId, userId)
                .one();
        if (myInvite == null) {
            return;
        }
        // 判断上级是否实名
        Long lv1UserId = myInvite.getInvitId(), lv2UserId = null;
        ConsumerRealName lv1RealName = consumerRealNameService.getUserRealNameOrNull(lv1UserId);
        if (lv1RealName == null) {
            return;
        }
        // 判断上级身份是否有该nft藏品对应配置
        UserIdentityPermWrench permWrench = userIdentityPermWrenchService.getEffective(lv1UserId, nftId);
        String nftTile = nftService.getNft(nftId).getTitle();
        BigDecimal lv1ReturnAmount = null;
        BigDecimal lv2ReturnAmount = null;
        if (permWrench != null && permWrench.getFromLevel1ReturnAmount().compareTo(BigDecimal.ZERO) > 0) {
            lv1ReturnAmount = permWrench.getFromLevel1ReturnAmount();
            // 根据配置信息奖励上级
            UserAssetWrenchReceive receive = new UserAssetWrenchReceive();
            receive.setUserId(lv1UserId);
            receive.setAmount(lv1ReturnAmount);
            receive.setIsReceive(0);
            receive.setNftId(nftId);
            receive.setFromUserId(userId);
            receive.setFromUserParentId(lv1UserId);
            receive.setType(WrenchReceiveTypeEnum.DIRECT_USE_NFT);
            receive.setRemark("直接好友使用" + nftTile + "*1");
            userAssetWrenchReceiveService.save(receive);
        }

        ConsumerInviteRecord lv1Invite = consumerInviteRecordService.lambdaQuery()
                .eq(ConsumerInviteRecord::getUserId, lv1UserId)
                .one();
        if (lv1Invite != null) {
            lv2UserId = lv1Invite.getInvitId();
            ConsumerRealName lv2RealName = consumerRealNameService.getUserRealNameOrNull(lv2UserId);
            if (lv2RealName != null) {
                // 判断上级身份是否有该nft藏品对应配置
                UserIdentityPermWrench permWrench2 = userIdentityPermWrenchService.getEffective(lv2UserId, nftId);
                if (permWrench2 != null && permWrench2.getFromLevel2ReturnAmount().compareTo(BigDecimal.ZERO) > 0) {
                    lv2ReturnAmount = permWrench2.getFromLevel2ReturnAmount();
                    // 根据配置信息奖励上上级
                    UserAssetWrenchReceive receive = new UserAssetWrenchReceive();
                    receive.setUserId(lv2UserId);
                    receive.setAmount(lv2ReturnAmount);
                    receive.setIsReceive(0);
                    receive.setNftId(nftId);
                    receive.setFromUserId(userId);
                    receive.setFromUserParentId(lv1UserId);
                    receive.setType(WrenchReceiveTypeEnum.INDIRECT_USE_NFT);
                    receive.setRemark("间接好友使用" + nftTile + "*1");
                    userAssetWrenchReceiveService.save(receive);
                }
            }
        }
        // 修改统计数据
        if (lv1ReturnAmount != null) {
            this.lambdaUpdate()
                    .setSql("to_upper_direct = to_upper_direct +" + lv1ReturnAmount)
                    .eq(UserAssetWrench::getUserId, userId)
                    .update();
            this.lambdaUpdate()
                    .setSql("pending = pending +" + lv1ReturnAmount)
                    .eq(UserAssetWrench::getUserId, lv1UserId)
                    .update();
        }

        if (lv2ReturnAmount != null) {
            this.lambdaUpdate()
                    .setSql("pending = pending +" + lv2ReturnAmount)
                    .eq(UserAssetWrench::getUserId, lv2UserId)
                    .update();
            this.lambdaUpdate()
                    .setSql("to_upper_indirect = to_upper_indirect +" + lv2ReturnAmount)
                    .eq(UserAssetWrench::getUserId, lv1UserId)
                    .update();
        }
    }

    /**
     * 修改钱包并插入记录
     *
     * @return
     */
    @Transactional
    public boolean updateAndAddRecord(UserAssetWrenchRecord record) {
        if (record.getUserId() == null || record.getDirection() == null || record.getAmount() == null
                || record.getChangeType() == null || record.getAmount().compareTo(BigDecimal.ZERO) < 1) {
            log.error("扳手更新记录：" + record);
            throw new ServiceException("扳手记录参数错误");
        }
        UserAssetWrench wrench = this.getByUserId(record.getUserId());
        if (record.getDirection() == WalletChangeDirectionEnum.OUT) {
            if (record.getAmount().compareTo(wrench.getAmount()) > 0) {
                throw new ServiceException("扳手余额不足");
            }
            record.setAmount(record.getAmount().negate());
        }
        boolean result = this.lambdaUpdate()
                .setSql("amount = amount +" + record.getAmount())
                .eq(UserAssetWrench::getUserId, record.getUserId())
                .apply("(amount + {0}) >= 0", record.getAmount())
                .update();
        if (result) {
            record.setAmountBefore(wrench.getAmount());
            record.setAmountAfter(wrench.getAmount().add(record.getAmount()));
            result = userAssetWrenchRecordService.save(record);
        }
        if (!result) {
            throw new ServiceException("扳手更新失败");
        }
        return result;
    }

    /**
     * 获取指定用户的扳手信息
     *
     * @param userId
     * @return
     */
    public UserAssetWrench getWrench(Long userId) {
        UserAssetWrench wrench = this.lambdaQuery().eq(UserAssetWrench::getUserId, userId).one();
        return Optional.ofNullable(wrench).orElse(new UserAssetWrench());
    }


    /**
     * 启动扳手工厂
     *
     * @param userId
     * @param dto
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public R upWrenchFactory(Long userId, upWrenchFactoryDto dto) {
        // 1.检查工厂状态
        UserIdentityRank identityRank = userIdentityRankService.getUserIdentityRank(userId);
        if (!identityRank.getIsOpenWrenchProduction()) {
            throw new ServiceException("您的用户身份无法生产扳手");
        }
        // 1.1 检查是否还有未完成的工厂
        UserWrenchProductionRecord record = getUserWrenchProductionRecord(userId);
        if (record != null && record.getGetAmount() == null) {
            log.error("扳手工厂启动非法操作");
            throw new ServiceException("非法操作");
        }

        // 2.查询启动套餐
        Long permWrenchProductionId = dto.getPermWrenchProductionId();
        LambdaQueryWrapper<UserIdentityPermWrenchProduction> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(UserIdentityPermWrenchProduction::getId, permWrenchProductionId);
        UserIdentityPermWrenchProduction wrenchProduction = userIdentityPermWrenchProductionService.getOne(lambdaQueryWrapper);
        // 3.增加扳手工厂记录
        SysUserWallet userWallet = sysUserWalletService.getWallet(userId, UserWalletEnum.INTEGRAL);
        if (userWallet.getAmount().compareTo(wrenchProduction.getExpendHotBeans()) < 0) {
            throw new ServiceException("热豆余额不足,无法充能");
        }
        UserWrenchProductionRecord wrenchProductionRecord = new UserWrenchProductionRecord();
        wrenchProductionRecord.setPermWrenchProductionId(wrenchProduction.getId());
        wrenchProductionRecord.setUserId(userId);
        wrenchProductionRecord.setPredictOutputWrench(wrenchProduction.getPredictOutputWrench());
        wrenchProductionRecord.setStartTime(LocalDateTime.now());
        wrenchProductionRecord.setExpendHotBeans(wrenchProduction.getExpendHotBeans());
        wrenchProductionRecord.setStatus(WrenchProductionTypeEnum.IN_PRODUCTION.getValue());
        wrenchProductionRecord.setPredictDay(wrenchProduction.getDayProduction());
        UserIdentityRank userIdentityRank = userIdentityRankService.getUserIdentityRank(userId);
        wrenchProductionRecord.setIdentityName(userIdentityRank.getIdentityName() + userIdentityRank.getName());
        userWrenchProductionRecordService.save(wrenchProductionRecord);
        Long wrenchProductionRecordId = wrenchProductionRecord.getId();
        // 4.更新热豆余额,增加热豆变动记录
        sysUserWalletService.reduce(userId, UserWalletEnum.INTEGRAL, wrenchProduction.getExpendHotBeans(), WalletChangeTypeEnum.WRENCH_CHARGE, wrenchProductionRecordId, "扳手工厂充能");
        return R.ok();
    }


    /**
     * 获取扳手累计产出 = 扳手记录已领取 + 此次已生产
     *
     * @return
     */
    public getWrenchAccruingVo getWrenchAccruing(Long userId) {
        getWrenchAccruingVo vo = new getWrenchAccruingVo();
        LambdaQueryWrapper<UserWrenchProductionRecord> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(UserWrenchProductionRecord::getUserId, userId);
        List<UserWrenchProductionRecord> recordList = userWrenchProductionRecordService.list(lambdaQueryWrapper);
        // 扳手记录已领取
        BigDecimal recordCount = new BigDecimal(0);
        if (recordList.size() == 0) {// 没有生产记录
            vo.setAllCount(BigDecimal.ZERO);
            vo.setProductionCount(BigDecimal.ZERO);
            return vo;
        }
        for (UserWrenchProductionRecord record : recordList) {
            if (record.getGetAmount() == null) {
                record.setGetAmount(BigDecimal.valueOf(0));
            }
            recordCount = recordCount.add(record.getGetAmount());
        }
        // ===========================================================================================================
        // 查询是否有最近的未领取的生产记录.但已经有产出了
        BigDecimal productionCount = getProductionCount(lambdaQueryWrapper, userId);
        vo.setProductionCount(productionCount);
        vo.setAllCount(recordCount.add(productionCount));
        return vo;
    }

    /**
     * 计算工厂目前已产出
     *
     * @param lambdaQueryWrapper
     * @return
     */
    private BigDecimal getProductionCount(LambdaQueryWrapper<UserWrenchProductionRecord> lambdaQueryWrapper, Long userid) {
        // 工厂正在生产中,计算已产出
        lambdaQueryWrapper.eq(UserWrenchProductionRecord::getStatus, WrenchProductionTypeEnum.IN_PRODUCTION.getValue())
                .or()
                .eq(UserWrenchProductionRecord::getUserId, userid)
                .ne(UserWrenchProductionRecord::getStatus, WrenchProductionTypeEnum.ALREADY_GET.getValue())
                .ne(UserWrenchProductionRecord::getStatus, WrenchProductionTypeEnum.EARLY_GET);
        UserWrenchProductionRecord record = userWrenchProductionRecordService.getOne(lambdaQueryWrapper);
        BigDecimal productionCount = new BigDecimal(0);
        if (record == null) {
            return productionCount;
        }
        // 平均每天生产
        BigDecimal avgDays = record.getPredictOutputWrench().divide(BigDecimal.valueOf(record.getPredictDay()), 2, RoundingMode.HALF_UP);
        // 平均每小时生产
        BigDecimal avgHours = record.getPredictOutputWrench().divide(BigDecimal.valueOf(record.getPredictDay() * 24), 2, RoundingMode.HALF_UP);
        // 结束时间
        long endTime = record.getStartTime().plusDays(record.getPredictDay()).toInstant(ZoneOffset.of("+8")).toEpochMilli();
        // 结算时间
        LocalDateTime time = record.getStartTime().plusDays(record.getPredictDay() + 1);
        long closeTime = LocalDateTime.of(time.toLocalDate(), LocalTime.MIN).toInstant(ZoneOffset.of("+8")).toEpochMilli();
        // 当前时间
        long now = LocalDateTime.now().toInstant(ZoneOffset.of("+8")).toEpochMilli();
        if (now > closeTime) { // 待领取
            productionCount = record.getPredictOutputWrench();
        } else if (now > endTime) { // 结算期 缺少最后一天的收益
            Integer predictDay = record.getPredictDay();
            BigDecimal daysCount = avgDays.multiply(BigDecimal.valueOf(predictDay - 1)).setScale(2, RoundingMode.HALF_UP);
            LocalDateTime atTime = record.getStartTime().plusDays(1).toLocalDate().atTime(0, 0, 0);
            long between = ChronoUnit.HOURS.between(record.getStartTime(), atTime);
            BigDecimal hoursCount = avgHours.multiply(BigDecimal.valueOf(between));
            productionCount = daysCount.add(hoursCount);
//            LocalDateTime dateTime = record.getStartTime().plusDays(1).toLocalDate().atTime(0, 0, 0);
//            long hour = ChronoUnit.HOURS.between(record.getStartTime(), dateTime);
//            BigDecimal multiply = avgHours.multiply(BigDecimal.valueOf(hour)).setScale(2,RoundingMode.HALF_UP);
//            productionCount = record.getPredictOutputWrench().subtract(multiply);
        } else { // 生产中
            long between = ChronoUnit.DAYS.between(record.getStartTime().plusDays(1).toLocalDate(), LocalDateTime.now().toLocalDate());
            if (between >= 0) {
                // 计算整天收益
                BigDecimal days = new BigDecimal(0);
                if (between > 0) {
                    days = avgDays.multiply(BigDecimal.valueOf(between)).setScale(2, RoundingMode.HALF_UP);
                }
                // 计算第一天的小时收益
                LocalDateTime startTime = record.getStartTime();
                LocalDateTime atTime = startTime.toLocalDate().plusDays(1).atTime(0, 0, 0);
                // 今天结束时间
                // 距离今天结束差多少小时
                long between1 = ChronoUnit.HOURS.between(startTime, atTime);
                BigDecimal hours = avgHours.multiply(BigDecimal.valueOf(between1)).setScale(2, RoundingMode.HALF_UP);
                productionCount = days.add(hours);
            }
        }
        return productionCount;
    }

    /**
     * 扳手工厂领取扳手
     *
     * @param userId
     */
    @Transactional(rollbackFor = Exception.class)
    public WrenchFactoryReceiveAwardVo wrenchFactoryReceiveAward(Long userId) {
        WrenchFactoryReceiveAwardVo vo = new WrenchFactoryReceiveAwardVo();
        // 计算已产出的产量
        LambdaQueryWrapper<UserWrenchProductionRecord> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(UserWrenchProductionRecord::getUserId, userId);
        BigDecimal productionCount = getProductionCount(lambdaQueryWrapper, userId);
        vo.setReceiveCount(productionCount);
        // 1.增加扳手钱包余额并更新记录
        userAssetWrenchRecordService.updateWrenchBalance(userId, WalletWrenchChangeTypeEnum.WRENCH_FACTORY, WalletChangeDirectionEnum.IN, productionCount, 10L, "扳手工厂领取");
        // 2.更新扳手工厂记录
        UserWrenchProductionRecord userWrenchProductionRecord = getUserWrenchProductionRecord(userId);
        // 如果实际领取金额不为null  则已被领取
        if (userWrenchProductionRecord.getGetAmount() != null) {
            throw new ServiceException("订单已被领取");
        }
        LocalDateTime startTime = userWrenchProductionRecord.getStartTime();
        Integer predictDay = userWrenchProductionRecord.getPredictDay();
        LocalDateTime now = LocalDateTime.now();
        if (ChronoUnit.DAYS.between(startTime, now) <= predictDay) {
            userWrenchProductionRecord.setStatus(WrenchProductionTypeEnum.EARLY_GET.getValue());
            vo.setStatus(WrenchProductionTypeEnum.EARLY_GET.getValue());
        } else {
            userWrenchProductionRecord.setStatus(WrenchProductionTypeEnum.ALREADY_GET.getValue());
            vo.setStatus(WrenchProductionTypeEnum.ALREADY_GET.getValue());
        }
        userWrenchProductionRecord.setEndTime(now);
        userWrenchProductionRecord.setGetAmount(productionCount);
        userWrenchProductionRecordService.updateById(userWrenchProductionRecord);
        return vo;
    }

    /**
     * 扳手工厂领取记录
     *
     * @param userId
     */
    public IPage<UserWrenchProductionRecord> wrenchFactoryRecord(Page<UserWrenchProductionRecord> page,Long userId) {
        LambdaQueryWrapper<UserWrenchProductionRecord> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(UserWrenchProductionRecord::getUserId, userId);
        lambdaQueryWrapper.ne(UserWrenchProductionRecord::getStatus, WrenchProductionTypeEnum.IN_PRODUCTION);
        lambdaQueryWrapper.ne(UserWrenchProductionRecord::getStatus, WrenchProductionTypeEnum.WAIT_GET);
        lambdaQueryWrapper.ne(UserWrenchProductionRecord::getStatus, WrenchProductionTypeEnum.CLOSING);
        lambdaQueryWrapper.orderByDesc(UserWrenchProductionRecord::getEndTime);
        return userWrenchProductionRecordService.page(page,lambdaQueryWrapper);
    }

    /**
     * 获取本次生产剩余时间和状态
     *
     *
     * @return
     */
    public WrenchGetProductionStatusAndTimeVo getProductionStatusAndTime(Long userId) {
        WrenchGetProductionStatusAndTimeVo vo = new WrenchGetProductionStatusAndTimeVo();
        LambdaQueryWrapper<UserWrenchProductionRecord> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(UserWrenchProductionRecord::getUserId, userId)
                .ne(UserWrenchProductionRecord::getStatus, WrenchProductionTypeEnum.ALREADY_GET)
                .ne(UserWrenchProductionRecord::getStatus, WrenchProductionTypeEnum.EARLY_GET);
        UserWrenchProductionRecord record = userWrenchProductionRecordService.getOne(queryWrapper);
        if (record == null) {
            return null;
        }
        // 开始时间
        long startTime = record.getStartTime().toInstant(ZoneOffset.of("+8")).toEpochMilli();
        // 结束时间
        long endTime = record.getStartTime().plusDays(record.getPredictDay()).toInstant(ZoneOffset.of("+8")).toEpochMilli();
        // 结算时间
        LocalDateTime time = record.getStartTime().plusDays(record.getPredictDay() + 1);
        long closeTime = LocalDateTime.of(time.toLocalDate(), LocalTime.MIN).toInstant(ZoneOffset.of("+8")).toEpochMilli();
        // 当前时间
        long now = LocalDateTime.now().toInstant(ZoneOffset.of("+8")).toEpochMilli();
        vo.setStatus(record.getStatus());
        vo.setCloseTime(closeTime);
        vo.setEndTime(endTime);
        vo.setStartTime(startTime);
        vo.setNowTime(now);
        vo.setPredictOutputWrench(record.getPredictOutputWrench());
        vo.setPredictDay(record.getPredictDay());
        return vo;
    }


    /**
     * 获取最新扳手生产记录
     *
     * @param userId
     * @return
     */
    private UserWrenchProductionRecord getUserWrenchProductionRecord(Long userId) {
        LambdaQueryWrapper<UserWrenchProductionRecord> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper
                .eq(UserWrenchProductionRecord::getUserId, userId)
//                .ne(UserWrenchProductionRecord::getStatus, WrenchProductionTypeEnum.ALREADY_GET.getValue())
//                .ne(UserWrenchProductionRecord::getStatus, WrenchProductionTypeEnum.EARLY_GET.getValue())
                .orderByDesc(UserWrenchProductionRecord::getStartTime).last("limit 1");
        // 取出生产记录
        return userWrenchProductionRecordService.getOne(queryWrapper);
    }

    /**
     * 获取扳手生产总领取金额
     * @param userId
     * @return
     */
    public BigDecimal wrenchFactoryGiveAmount(Long userId) {
        LambdaQueryWrapper<UserWrenchProductionRecord> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(UserWrenchProductionRecord::getUserId, userId);
        lambdaQueryWrapper.ne(UserWrenchProductionRecord::getStatus, WrenchProductionTypeEnum.IN_PRODUCTION);
        lambdaQueryWrapper.ne(UserWrenchProductionRecord::getStatus, WrenchProductionTypeEnum.WAIT_GET);
        lambdaQueryWrapper.ne(UserWrenchProductionRecord::getStatus, WrenchProductionTypeEnum.CLOSING);
        lambdaQueryWrapper.orderByDesc(UserWrenchProductionRecord::getEndTime);
        List<UserWrenchProductionRecord> list = userWrenchProductionRecordService.list(lambdaQueryWrapper);
        BigDecimal bigDecimal = new BigDecimal(0);
        for (UserWrenchProductionRecord record : list) {
            if (record.getGetAmount() != null){
                bigDecimal = bigDecimal.add(record.getGetAmount());
            }
        }
        return bigDecimal;
    }
}
